﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Reflection;

namespace MarioArenaLevelEditor
{
    public partial class Form1 : Form
    {
        private PictureBox selectedPB = null;
        private string oldWidth;
        private string oldHeight;
        public Form1()
        {
            InitializeComponent();
            //Set double buffering for the drawing panel
            SetDoubleBuffered(panelMap);
            //Load the textures
            TextureManager.LoadTextures();
            //Constuct the map singleton
            UI.shareComponents(this.panelMap, this.tbWidth, buttonScrollLeft, buttonScrollRight, buttonScrollUp, buttonScrollDown);
            oldWidth = tbWidth.Text;
            oldHeight = tbHeight.Text;
        }


        private void buttonScrollLeft_Click(object sender, EventArgs e)
        {
            Map.Instance.MoveLeft();
            panelMap.Invalidate();
        }
        private void buttonScrollRight_Click(object sender, EventArgs e)
        {
            Map.Instance.MoveRight();
            panelMap.Invalidate();
        }
        private void buttonScrollUp_Click(object sender, EventArgs e)
        {
            Map.Instance.MoveUp();
            panelMap.Invalidate();
        }
        private void buttonScrollDown_Click(object sender, EventArgs e)
        {
            Map.Instance.MoveDown();
            panelMap.Invalidate();
        }

        private void panelMap_Paint(object sender, PaintEventArgs e)
        {
            Map.Instance.Draw(e);
        }

        private void panelMap_MouseDown(object sender, MouseEventArgs e)
        {
            Map.Instance.MouseDown(e.Button == MouseButtons.Left);
            panelMap.Focus();
        }

        private void panelMap_MouseUp(object sender, MouseEventArgs e)
        {
            Map.Instance.MouseUp();
            panelMap.Invalidate();
        }

        private void panelMap_MouseMove(object sender, MouseEventArgs e)
        {
            if (Map.Instance.MouseMove())
                panelMap.Invalidate();
        }

        public static void SetDoubleBuffered(Control control)
        {
            // set instance non-public property with name "DoubleBuffered" to true
            typeof(Control).InvokeMember("DoubleBuffered",
                BindingFlags.SetProperty | BindingFlags.Instance | BindingFlags.NonPublic,
                null, control, new object[] { true });
        }

        private void pbTexture_Click(object sender, EventArgs e)
        {
            PictureBox pictureBox = (PictureBox)sender;
            string tilevalue = pictureBox.Tag.ToString();

            try
            {
                int tileType = Convert.ToInt32(tilevalue);
                SelectedPBChanged(this.selectedPB, pictureBox);
                //Change 'brush'
                Map.Instance.SelectedTileType = tileType;
                Console.WriteLine("Selected: " + tileType);
            }
            catch (Exception exc) { Console.WriteLine("Error when converting tile tag to int."); }
        }

        private void SelectedPBChanged(PictureBox pbOld, PictureBox pbNew)
        {
            if (pbOld != null)
                pbOld.BackColor = Color.White;
            pbNew.BackColor = Color.Black;
            this.selectedPB = pbNew;
        }

        private void buttonApplyWidth_Click(object sender, EventArgs e)
        {
            int minSize = 36;
            int maxSize = 150;
            int size;
            try
            {
                size = Convert.ToInt32(tbWidth.Text);
                if (size > maxSize)
                {
                    size = maxSize;
                    tbWidth.Text = maxSize.ToString();
                }
                else if (size < minSize)
                {
                    size = minSize;
                    tbWidth.Text = minSize.ToString();
                }

                if (ConfirmMessage("Confirm change in width", "Do you wish to apply the width change from " + oldWidth + " to " + tbWidth.Text + "?"))
                {
                    int widthBeforeResize = Map.Instance.GridWidth;
                    Map.Instance.ChangeSizeX(size);
                    buttonApplyWidth.Enabled = false;
                    oldWidth = tbWidth.Text;
                    if (size > widthBeforeResize)
                        buttonScrollRight.Enabled = true;
                    else buttonScrollRight.Enabled = false;
                    panelMap.Invalidate();
                }
                else tbWidth.Text = oldWidth;

            }
            catch (Exception exc) { }
            panelMap.Focus();
        }

        private void buttonApplyHeight_Click(object sender, EventArgs e)
        {
            int minSize = 24;
            int maxSize = 100;
            int size;
            try
            {
                size = Convert.ToInt32(tbHeight.Text);
                if (size > maxSize)
                {
                    size = maxSize;
                    tbHeight.Text = maxSize.ToString();
                }
                else if (size < minSize)
                {
                    size = minSize;
                    tbHeight.Text = minSize.ToString();
                }

                if (ConfirmMessage("Confirm change in height", "Do you wish to apply the height change from " + oldHeight + " to " + tbHeight.Text + "?"))
                {
                    int heightBeforeResize = Map.Instance.GridHeight;
                    Map.Instance.ChangeSizeY(size);
                    buttonApplyHeight.Enabled = false;
                    oldHeight = tbHeight.Text;
                    if (size > heightBeforeResize)
                        buttonScrollUp.Enabled = true;
                    else buttonScrollUp.Enabled = false;
                }
                else tbHeight.Text = oldWidth; //change cancelled
                panelMap.Invalidate();
            }
            catch (Exception exc) { }
            panelMap.Focus();
        }

        private bool ConfirmMessage(string title, string message)
        {
            DialogResult confirmResult = MessageBox.Show(message, title, MessageBoxButtons.YesNo);
            return confirmResult == DialogResult.Yes;
        }

        private void tbWidth_TextChanged(object sender, EventArgs e)
        {
            if (ContainsOnlyDigits(tbWidth.Text))
            {
                buttonApplyWidth.Enabled = true;
            }
            else tbWidth.Text = oldWidth;
        }
        private void tbHeight_TextChanged(object sender, EventArgs e)
        {
            if (ContainsOnlyDigits(tbHeight.Text))
            {
                buttonApplyHeight.Enabled = true;
            }
            else tbHeight.Text = oldHeight;
        }

        private bool ContainsOnlyDigits(string text)
        {
            char[] numbers = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' };
            char[] charArray = text.ToCharArray();
            foreach (char c in charArray)
            {
                if (!numbers.Contains(c))
                    return false;
            }
            return true;
        }

        private void cbShowGrid_CheckedChanged(object sender, EventArgs e)
        {
            Map.Instance.showGrid = cbShowGrid.Checked;
            panelMap.Invalidate();
        }

        private void buttonGridColor_Click(object sender, EventArgs e)
        {
            DialogResult result = colorDialogGrid.ShowDialog();
            // See if user pressed ok.
            if (result == DialogResult.OK)
            {
                // Set form background to the selected color.
                buttonGridColor.BackColor = colorDialogGrid.Color;
                Map.Instance.GridPen = new Pen(colorDialogGrid.Color);
                panelMap.Invalidate();
            }
        }

        private void buttonSave_Click(object sender, EventArgs e)
        {
            
            SaveFileDialog saveDialog = new SaveFileDialog();
            saveDialog.Filter = "Mario Arena files (*.ma)|";
            if (saveDialog.ShowDialog() == DialogResult.OK)
            {
                string fileExtension = ".ma";
                string filepath = saveDialog.FileName;
                string saveData = Map.Instance.GenerateFile();
                if (saveData != null)
                {

                    //Write to file
                    StreamWriter file = new System.IO.StreamWriter(filepath + fileExtension);
                    file.Write(saveData);
                    file.Close();
                }
                else MessageBox.Show("Level cannot be saved. One or more spawnpoints must be placed first.");
            }
            
        }

        private void Form1_KeyDown(object sender, KeyEventArgs e)
        {
            Keys pressedKey = e.KeyCode;
            if (pressedKey.Equals(Keys.W) || pressedKey.Equals(Keys.Up))
                buttonScrollUp.PerformClick();
            if (pressedKey.Equals(Keys.S) || pressedKey.Equals(Keys.Down))
                buttonScrollDown.PerformClick();
            if (pressedKey.Equals(Keys.A) || pressedKey.Equals(Keys.Left))
                buttonScrollLeft.PerformClick();
            if (pressedKey.Equals(Keys.D) || pressedKey.Equals(Keys.Right))
                buttonScrollRight.PerformClick();
            e.Handled = true;
        }

        

        

        


    }
}
